package upm.pb4agent.team5.common;

import jade.core.AID;
import jade.core.behaviours.CyclicBehaviour;
import jade.lang.acl.ACLMessage;

import java.util.Date;

import upm.pb4agent.ontology.RaceStarted;
import upm.pb4agent.ontology.Registration;
import upm.pb4agent.ontology.RegistrationForm;
import upm.pb4agent.team5.enumeration.ConfigProperty;
import upm.pb4agent.team5.util.ConfigFile;

public class BRegistrationDeskManageInscription extends CyclicBehaviour {
	private static final long serialVersionUID = -4274791826021480089L;
	private static final int WAIT_PER_SEARCH = 100; // Milliseconds
	private static final long WAIT_FOR_START_RACE; // Milliseconds
	
	private RegistrationDesk registrationDesk = null;
	private Date registerTime = null;
	private boolean inscriptionClosed = false;

	static {
		WAIT_FOR_START_RACE = Long.parseLong(
				ConfigFile.getProperty(ConfigProperty.registration_period.name())
			); 
	}
	
	public BRegistrationDeskManageInscription(RegistrationDesk registrationDesk, Date registerTime) {
		this.registrationDesk = registrationDesk;
		this.registerTime = registerTime;
	}
	
	public void action() {
		ACLMessage msg = registrationDesk.receive(); // Async because time has to pass even if there are not messages

		long timeDiff = (new Date()).getTime() - registerTime.getTime(); 
		if (!inscriptionClosed && timeDiff >= WAIT_FOR_START_RACE) {
			System.out.println(registrationDesk.getLocalName() + ": Inscription closed");
			inscriptionClosed = true;
			
			startRace();
			System.out.println(registrationDesk.getLocalName() + ": Race started message sent");
		}

		try {
			if (msg != null && msg.getPerformative() == ACLMessage.REQUEST) {
				Registration registration = (Registration) registrationDesk.getConcept(msg);
				RegistrationForm registrationForm = registration.getRegistrationForm();
				
				// If has been waiting for more than 5 minutes, it does not receive inscriptions anymore
				if (inscriptionClosed) { // Team rejected
					System.err.println(registrationDesk.getLocalName() + ": Team " + registrationForm.getTeamID().getValue() + " refused due to time over");
					
					// Sending refuse
					registrationDesk.send(msg.getSender(), ACLMessage.REFUSE, Registration.class.getSimpleName());
				} else { // Team accepted
					// Previous casting is enough for validating RegistrationForm 
					System.out.println(registrationDesk.getLocalName() + ": Team " + registrationForm.getTeamID().getValue() + " inscription is accepted");

					// Sending accepted inform to the Manager
					registrationDesk.send(msg.getSender(), ACLMessage.INFORM, Registration.class.getSimpleName());
					
					// Creating Watcher
					AID watcher = registrationDesk.createAgent(Watcher.class, Watcher.DF_NAME + registrationForm.getTeamID().getValue(), null, true);

					// Sending team details to Watcher
					registrationDesk.send(registration, watcher, ACLMessage.INFORM);
					System.out.println(registrationDesk.getLocalName() + ": Watcher informed about new inscription, teamID: " + registrationForm.getTeamID().getValue());
				}
			}

			// If inscription is closed just block for new messages, if not time has to continue passing
			if (!inscriptionClosed)  
				registrationDesk.doWait(WAIT_PER_SEARCH);
			else
				block();
			
		} catch (Exception ue) {
			// Sending NOT_UNDERSTOOD
			try {
				registrationDesk.send(msg.getSender(), ACLMessage.NOT_UNDERSTOOD, Registration.class.getSimpleName());
			} catch (Exception e) {
				System.err.println(registrationDesk.getLocalName() + ": Error sending NOT_UNDERSTOOD to " + msg.getSender().getLocalName());
			}
		}
	}
	
	private void startRace() {
		try {
			AID referee = registrationDesk.findAID(Referee.DF_NAME);
			registrationDesk.send(new RaceStarted(), referee, ACLMessage.INFORM);
			
		} catch (Exception e) {
			System.err.println(registrationDesk.getLocalName() + ": Cannot send start race message to " + Referee.DF_NAME);
		} 
		
	}
}
